* `GtkMenuButton` has a single CSS node with name `menubutton`
* which contains a `button` node with a `.toggle` style class.
*
+ * If the button contains only an icon or an arrow, it will have the
+ * `.image-button` style class, if it contains both, it will have the
+ * `.arrow-button` style class.
+ *
* Inside the toggle button content, there is an `arrow` node for
* the indicator, which will carry one of the `.none`, `.up`, `.down`,
* `.left` or `.right` style classes to indicate the direction that
#include "gtkactionable.h"
#include "gtkbuiltiniconprivate.h"
#include "gtkintl.h"
+#include "gtkimage.h"
#include "gtkmain.h"
#include "gtkmenubutton.h"
#include "gtkmenubuttonprivate.h"
GDestroyNotify create_popup_destroy_notify;
GtkWidget *label_widget;
+ GtkWidget *image_widget;
GtkWidget *arrow_widget;
GtkArrowType arrow_type;
+ gboolean always_show_arrow;
gboolean primary;
};
PROP_DIRECTION,
PROP_POPOVER,
PROP_ICON_NAME,
+ PROP_ALWAYS_SHOW_ARROW,
PROP_LABEL,
PROP_USE_UNDERLINE,
PROP_HAS_FRAME,
case PROP_ICON_NAME:
gtk_menu_button_set_icon_name (self, g_value_get_string (value));
break;
+ case PROP_ALWAYS_SHOW_ARROW:
+ gtk_menu_button_set_always_show_arrow (self, g_value_get_boolean (value));
+ break;
case PROP_LABEL:
gtk_menu_button_set_label (self, g_value_get_string (value));
break;
case PROP_ICON_NAME:
g_value_set_string (value, gtk_menu_button_get_icon_name (GTK_MENU_BUTTON (object)));
break;
+ case PROP_ALWAYS_SHOW_ARROW:
+ g_value_set_boolean (value, gtk_menu_button_get_always_show_arrow (self));
+ break;
case PROP_LABEL:
g_value_set_string (value, gtk_menu_button_get_label (GTK_MENU_BUTTON (object)));
break;
NULL,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+ /**
+ * GtkMenuButton:always-show-arrow: (attributes org.gtk.Property.get=gtk_menu_button_get_always_show_arrow org.gtk.Property.set=gtk_menu_button_set_always_show_arrow)
+ *
+ * Whether to show a dropdown arrow even when using an icon.
+ *
+ * Since: 4.4
+ */
+ menu_button_props[PROP_ALWAYS_SHOW_ARROW] =
+ g_param_spec_boolean ("always-show-arrow",
+ P_("Always Show Arrow"),
+ P_("Whether to show a dropdown arrow even when using an icon"),
+ FALSE,
+ GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
/**
* GtkMenuButton:label: (attributes org.gtk.Property.get=gtk_menu_button_get_label org.gtk.Property.set=gtk_menu_button_set_label)
*
gtk_widget_hide (arrow);
}
+static void
+update_style_classes (GtkMenuButton *menu_button)
+{
+ if (menu_button->arrow_widget == gtk_button_get_child (GTK_BUTTON (menu_button->button)) ||
+ (menu_button->image_widget && !menu_button->always_show_arrow))
+ gtk_widget_add_css_class (menu_button->button, "image-button");
+ else
+ gtk_widget_remove_css_class (menu_button->button, "image-button");
+
+ if (menu_button->image_widget && menu_button->always_show_arrow)
+ gtk_widget_add_css_class (menu_button->button, "arrow-button");
+ else
+ gtk_widget_remove_css_class (menu_button->button, "arrow-button");
+}
+
+static void
+update_arrow (GtkMenuButton *menu_button)
+{
+ gboolean has_only_arrow, is_text_button;
+
+ if (menu_button->arrow_widget == NULL)
+ return;
+
+ has_only_arrow = menu_button->arrow_widget == gtk_button_get_child (GTK_BUTTON (menu_button->button));
+ is_text_button = menu_button->label_widget != NULL;
+
+ set_arrow_type (menu_button->arrow_widget,
+ menu_button->arrow_type,
+ has_only_arrow ||
+ ((is_text_button || menu_button->always_show_arrow) &&
+ (menu_button->arrow_type != GTK_ARROW_NONE)));
+
+ update_style_classes (menu_button);
+}
+
static void
add_arrow (GtkMenuButton *self)
{
GtkWidget *arrow;
arrow = gtk_builtin_icon_new ("arrow");
+ gtk_widget_set_halign (arrow, GTK_ALIGN_CENTER);
set_arrow_type (arrow, self->arrow_type, TRUE);
gtk_button_set_child (GTK_BUTTON (self->button), arrow);
self->arrow_widget = arrow;
gtk_widget_set_parent (self->button, GTK_WIDGET (self));
g_signal_connect_swapped (self->button, "toggled", G_CALLBACK (gtk_menu_button_toggled), self);
add_arrow (self);
+ update_style_classes (self);
gtk_widget_set_sensitive (self->button, FALSE);
gtk_menu_button_set_direction (GtkMenuButton *menu_button,
GtkArrowType direction)
{
- gboolean is_image_button;
-
g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
if (menu_button->arrow_type == direction)
menu_button->arrow_type = direction;
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_DIRECTION]);
- /* Is it custom content? We don't change that */
- is_image_button = menu_button->label_widget == NULL;
- if (is_image_button && (menu_button->arrow_widget != gtk_button_get_child (GTK_BUTTON (menu_button->button))))
- return;
-
- set_arrow_type (menu_button->arrow_widget,
- menu_button->arrow_type,
- is_image_button || (menu_button->arrow_type != GTK_ARROW_NONE));
+ update_arrow (menu_button);
update_popover_direction (menu_button);
}
gtk_menu_button_set_icon_name (GtkMenuButton *menu_button,
const char *icon_name)
{
+ GtkWidget *box, *image_widget, *arrow;
+
g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
g_object_freeze_notify (G_OBJECT (menu_button));
if (gtk_menu_button_get_label (menu_button))
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_LABEL]);
- gtk_button_set_icon_name (GTK_BUTTON (menu_button->button), icon_name);
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
+
+ image_widget = g_object_new (GTK_TYPE_IMAGE,
+ "accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION,
+ "icon-name", icon_name,
+ NULL);
+ menu_button->image_widget = image_widget;
+
+ arrow = gtk_builtin_icon_new ("arrow");
+ menu_button->arrow_widget = arrow;
+
+ gtk_box_append (GTK_BOX (box), image_widget);
+ gtk_box_append (GTK_BOX (box), arrow);
+ gtk_button_set_child (GTK_BUTTON (menu_button->button), box);
+
+ menu_button->label_widget = NULL;
+
+ update_arrow (menu_button);
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_ICON_NAME]);
{
g_return_val_if_fail (GTK_IS_MENU_BUTTON (menu_button), NULL);
- return gtk_button_get_icon_name (GTK_BUTTON (menu_button->button));
+ if (menu_button->image_widget)
+ return gtk_image_get_icon_name (GTK_IMAGE (menu_button->image_widget));
+
+ return NULL;
+}
+
+/**
+ * gtk_menu_button_set_always_show_arrow: (attributes org.gtk.Method.set_property=always-show-arrow)
+ * @menu_button: a `GtkMenuButton`
+ * @always_show_arrow: hether to show a dropdown arrow even when using an icon
+ *
+ * Sets whether to show a dropdown arrow even when using an icon.
+ *
+ * Since: 4.4
+ */
+void
+gtk_menu_button_set_always_show_arrow (GtkMenuButton *menu_button,
+ gboolean always_show_arrow)
+{
+ g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
+
+ always_show_arrow = !!always_show_arrow;
+
+ if (always_show_arrow == menu_button->always_show_arrow)
+ return;
+
+ menu_button->always_show_arrow = always_show_arrow;
+
+ update_arrow (menu_button);
+
+ g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_ALWAYS_SHOW_ARROW]);
+}
+
+/**
+ * gtk_menu_button_get_always_show_arrow: (attributes org.gtk.Method.get_property=always-show-arrow)
+ * @menu_button: a `GtkMenuButton`
+ *
+ * Gets whether to show a dropdown arrow even when using an icon.
+ *
+ * Returns: whether to show a dropdown arrow even when using an icon
+ *
+ * Since: 4.4
+ */
+gboolean
+gtk_menu_button_get_always_show_arrow (GtkMenuButton *menu_button)
+{
+ g_return_val_if_fail (GTK_IS_MENU_BUTTON (menu_button), FALSE);
+
+ return menu_button->always_show_arrow;
}
/**
gtk_widget_set_halign (label_widget, GTK_ALIGN_CENTER);
arrow = gtk_builtin_icon_new ("arrow");
menu_button->arrow_widget = arrow;
- set_arrow_type (arrow, menu_button->arrow_type, menu_button->arrow_type != GTK_ARROW_NONE);
gtk_box_append (GTK_BOX (box), label_widget);
gtk_box_append (GTK_BOX (box), arrow);
gtk_button_set_child (GTK_BUTTON (menu_button->button), box);
menu_button->label_widget = label_widget;
+ menu_button->image_widget = NULL;
+
+ update_arrow (menu_button);
+
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_LABEL]);
g_object_thaw_notify (G_OBJECT (menu_button));
const char *
gtk_menu_button_get_label (GtkMenuButton *menu_button)
{
- GtkWidget *child;
-
g_return_val_if_fail (GTK_IS_MENU_BUTTON (menu_button), NULL);
- child = gtk_button_get_child (GTK_BUTTON (menu_button->button));
- if (GTK_IS_BOX (child))
- {
- child = gtk_widget_get_first_child (child);
- return gtk_label_get_label (GTK_LABEL (child));
- }
+ if (menu_button->label_widget)
+ return gtk_label_get_label (GTK_LABEL (menu_button->label_widget));
return NULL;
}